package com.cloud.haiyan_admin.annotion.AuthorityVerify;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cloud.haiyan_base.enums.EMenuType;
import com.cloud.haiyan_base.enums.EStatus;
import com.cloud.haiyan_base.global.ECode;
import com.cloud.haiyan_commons.entity.Admin;
import com.cloud.haiyan_commons.entity.CategoryMenu;
import com.cloud.haiyan_commons.entity.Role;
import com.cloud.haiyan_utils.JsonUtils;
import com.cloud.haiyan_utils.RedisUtil;
import com.cloud.haiyan_utils.ResultUtil;
import com.cloud.haiyan_utils.StringUtils;
import com.cloud.haiyan_xo.global.MessageConf;
import com.cloud.haiyan_xo.global.RedisConf;
import com.cloud.haiyan_xo.global.SQLConf;
import com.cloud.haiyan_xo.global.SysConf;
import com.cloud.haiyan_xo.service.AdminService;
import com.cloud.haiyan_xo.service.CategoryMenuService;
import com.cloud.haiyan_xo.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

//权限校验 切面实现

@Aspect
@Component
@Slf4j
public class AuthorityVerifyAspect {

    @Autowired
    CategoryMenuService categoryMenuService;

    @Autowired
    RoleService roleService;

    @Autowired
    AdminService adminService;

    @Autowired
    RedisUtil redisUtil;

    @Pointcut(value = "@annotation(authorityVerify)")
    public void pointcut(AuthorityVerify authorityVerify) {//声明一个切入点，切入的时机是调用这个注解时

    }

    @Around(value = "pointcut(authorityVerify)")//环绕通知，切点切入后执行的操作
    public Object doAround(ProceedingJoinPoint joinPoint, AuthorityVerify authorityVerify) throws Throwable {

        ServletRequestAttributes attribute = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = attribute.getRequest();

        //获取请求路径
        String url = request.getRequestURI();

        // 解析出请求者的ID和用户名
        String adminUid = request.getAttribute(SysConf.ADMIN_UID).toString();

        String visitUrl = redisUtil.get(RedisConf.ADMIN_VISIT_MENU + RedisConf.SEGMENTATION + adminUid);

        List<String> urlList = new ArrayList<>();

        if (StringUtils.isNotEmpty(visitUrl)) {
            // 从Redis中获取
            urlList = JsonUtils.jsonToList(visitUrl, String.class);
        } else {
            // 查询数据库获取
            Admin admin = adminService.getById(adminUid);

            String roleUid = admin.getRoleUid();

            Role role = roleService.getById(roleUid);

            String caetgoryMenuUids = role.getCategoryMenuUids();

            String[] uids = caetgoryMenuUids.replace("[", "").replace("]", "").replace("\"", "").split(",");

            List<String> categoryMenuUids = new ArrayList<>(Arrays.asList(uids));//找到当前用户所属角色所能访问的所有菜单ID

            // 这里只需要查询访问的按钮
            QueryWrapper<CategoryMenu> queryWrapper = new QueryWrapper<>();
            queryWrapper.in(SQLConf.UID, categoryMenuUids);//匹配uid
            queryWrapper.eq(SQLConf.MENU_TYPE, EMenuType.BUTTON);//匹配打开的按钮
            queryWrapper.eq(SQLConf.STATUS, EStatus.ENABLE);//匹配状态激活的按钮
            List<CategoryMenu> buttonList = categoryMenuService.list(queryWrapper);//最后获取结果

            for (CategoryMenu item : buttonList) {
                if (StringUtils.isNotEmpty(item.getUrl())) {
                    urlList.add(item.getUrl());
                }
            }
            // 将访问URL存储到Redis中
            redisUtil.setEx(RedisConf.ADMIN_VISIT_MENU + SysConf.REDIS_SEGMENTATION + adminUid, JsonUtils.objectToJson(urlList).toString(), 1, TimeUnit.HOURS);
        }

        // 判断该角色是否能够访问该接口
        boolean flag = false;
        for (String item : urlList) {
            if (url.equals(item)) {
                flag = true;
                log.info("用户拥有操作权限，访问的路径: {}，拥有的权限接口：{}", url, item);
                break;
            }
        }
        if (!flag) {
            log.info("用户不具有操作权限，访问的路径: {}", url);
            return ResultUtil.result(ECode.NO_OPERATION_AUTHORITY, MessageConf.RESTAPI_NO_PRIVILEGE);
        }

        //执行业务
        return joinPoint.proceed();
    }

}
